package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.zzyl.base.PageBean;
import com.zzyl.config.AliyunIotConfig;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliyunIotProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DevicePropertyStatusVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import com.zzyl.vo.QueryThingModelVo;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@Service
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private Client client;
    @Autowired
    private AliyunIotProperties aliyunIotProperties;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 产品列表数据同步
     *
     * @author YiSheep
     */
    @Override
    @SneakyThrows//将整个方法体放入一个try-catch块中，并捕获所有异常，如果有任何异常发生，它会将异常抛出。
    public void syncProductList() {
        //1、查询Iot平台的所有产品列表数据
        //创建请求对象
        QueryProductListRequest request = new QueryProductListRequest();
        request.setCurrentPage(1);
        request.setPageSize(200);
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        //发送请求
        QueryProductListResponse response = client.queryProductList(request);

        if (!response.body.success) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        //将结果拷贝到新的List集合中，并且将类型转换为ProductVo
        List<ProductVo> productVos = BeanUtil.copyToList(response.body.data.list.productInfo, ProductVo.class);
        //2、将结果存到redis中（string）
        stringRedisTemplate.opsForValue().set(CacheConstants.IOT_ALL_PRODUCT, JSON.toJSONString(productVos));
    }

    /**
     * 查询所有产品列表
     *
     * @return {@code List<ProductVo> }
     * @author YiSheep
     */
    @Override
    public List<ProductVo> allProduct() {
        //从redis取数据
        String json = stringRedisTemplate.opsForValue().get(CacheConstants.IOT_ALL_PRODUCT);

        //判断数据为空
        if (StrUtil.isBlank(json)) {
            return List.of();
        }

        //处理数据，将json字符串转为集合，存放的是ProductVo
        return JSON.parseArray(json, ProductVo.class);
    }

    /**
     * 注册设备
     *
     * @param deviceDto 设备dto
     * @author YiSheep
     */
    @SneakyThrows
    @Override
    public void RegisterDevice(DeviceDto deviceDto) {
        //检验设备名称是否重复
        int count = deviceMapper.countByDeviceName(deviceDto.getDeviceName());
        if (count > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //iot设备唯一标识
        String iotId = null;

        //1. 添加设备数据到阿里Iot平台
        try {
            RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
            request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            RegisterDeviceResponse response = client.registerDevice(request);
            if (!response.body.success) {
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }

            if (StrUtil.isBlank(response.body.data.iotId)) {
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
            //取出iotId
            iotId = response.body.data.iotId;
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }


        //2. 添加设备数据到数据库（设置iotId）
        try {
            //将dto数据拷贝到pojo中
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            //关联iot平台的设备id（iotId）
            device.setIotId(iotId);
            //int i = 1 / 0;

            //如果是随身设备，将physical_location_type设置为-1
            if(device.getLocationType()==0){
                device.setPhysicalLocationType(-1);//-1老人
            }

            deviceMapper.insert(device);
        } catch (Exception e) {
            //3. 如果添加到数据库失败，删除Iot平台的设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());//实例id
            deleteDeviceRequest.setIotId(iotId);
            client.deleteDevice(deleteDeviceRequest);
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_DATA_ERROR);
        }
    }

    /**
     * 分页查询设备
     *
     * @param dto 设备分页查询dto
     * @return {@code PageBean<DeviceVo> }
     * @author YiSheep
     */
    @Override
    public PageBean<DeviceVo> paegeQuery(DevicePageQueryDto dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        Page<DeviceVo> deviceVos = deviceMapper.selectPage(dto);
        PageBean<DeviceVo> pageBean = PageBean.of(deviceVos, DeviceVo.class);
        return pageBean;
    }

    /**
     * 查询设备详情
     *
     * @param deviceDto 设备dto
     * @return {@code DeviceVo }
     * @author YiSheep
     */
    @Override
    @SneakyThrows
    public DeviceVo QueryDeviceDetail(DeviceDto deviceDto) {
        //1、根据iotId查询阿里云Iot平台设备数据
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());//iot实例id
        request.setIotId(deviceDto.getIotId());//设备的iotId
        QueryDeviceDetailResponse queryDeviceDetailResponse = client.queryDeviceDetail(request);

        //2、根据iotId查询数据库设备数据

        DeviceVo deviceVo = deviceMapper.selectByIotId(deviceDto.getIotId());
        //3、将两部分数据合并到Vo中，返回
        BeanUtil.copyProperties(queryDeviceDetailResponse.body.data, deviceVo);
        return deviceVo;
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param request 查询设备属性状态请求
     * @return {@code DevicePropertyStatusVo }
     * @author YiSheep
     */
    @Override
    public DevicePropertyStatusVo queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        //设置iot实例id
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            //发送请求
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        //拷贝数据，返回
        DevicePropertyStatusVo vo = BeanUtil.toBean(response.body.data, DevicePropertyStatusVo.class);
        //将设备心率的属性值放在首位 //对集合排序，将心率放在最前面
        Collections.sort(vo.getList().getPropertyStatusInfo(), (o1, o2) -> (StrUtil.equalsIgnoreCase("HeartRate", o1.getIdentifier()) ? -1 : 1));
        return vo;
    }


    /**
     * 修改设备备注名称
     *
     * @param deviceDto 设备dto
     * @author YiSheep
     */
    @Transactional
    @Override
    public void UpdateDevice(DeviceDto deviceDto) {
        //检验数据库是否存在设备
        Device dbDevice = deviceMapper.selectByPrimaryKey(deviceDto.getId());
        if (ObjectUtil.isEmpty(dbDevice)) {
            throw new BaseException(BasicEnum.DEVICE_NOT_EXIST);
        }

        //更新数据库中设备信息
        try {
            //将dto转换为pojo
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            //判断位置类型：0随身设备，1固定设备        如果是随身设备，将物理位置设为-1
            if (NumberUtil.equals(device.getLocationType(), 0)) {
                device.setPhysicalLocationType(-1);//物理位置类型 0楼层 1房间 2床位 -1随身设备
            }
            deviceMapper.updateByPrimaryKeySelective(device);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        //调用物联网接口，更新云服务设备信息
        try {
            //创建请求对象
            BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
            //设置iot实例id
            request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            //将dto中的数据拷贝到请求对象中
            BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo nicknameInfo =
                    BeanUtil.toBean(deviceDto, BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo.class);
            //设置请求对象信息
            request.setDeviceNicknameInfo(Lists.newArrayList(nicknameInfo));
            //发送请求
            BatchUpdateDeviceNicknameResponse response = client.batchUpdateDeviceNickname(request);
            if (!Boolean.TRUE.equals(response.body.success)) {
                throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
    }

    /**
     * 删除设备
     *
     * @param deviceDto 设备dto
     * @author YiSheep
     */
    @Transactional
    @Override
    public void DeleteDevice(DeviceDto deviceDto) {
        DeleteDeviceRequest deleteDeviceRequest = BeanUtil.toBean(deviceDto, DeleteDeviceRequest.class);
        deleteDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        DeleteDeviceResponse deleteDeviceResponse;

        try {
            deviceMapper.deleteByIotId(deviceDto.getIotId());
            deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
            if (!deleteDeviceResponse.body.success) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }

    }

    /**
     * 查询产品的物模型定义数据
     *
     * @param request 查询事物模型发布请求
     * @return {@code QueryThingModelVo }
     * @author YiSheep
     */
    @SneakyThrows
    @Override
    public QueryThingModelVo queryThingModelPublished(QueryThingModelPublishedRequest request) {
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryThingModelPublishedResponse queryThingModelPublishedResponse = client.queryThingModelPublished(request);
        QueryThingModelVo queryThingModelVo = BeanUtil.toBean(queryThingModelPublishedResponse.body.data, QueryThingModelVo.class);
        return queryThingModelVo;
    }
}
